# file: D:\python-project\Well_Data_visualization_program\曹锋\src\ui\curve_data_dialog.py
from PySide6.QtWidgets import (
    QDialog, QVBoxLayout, QTableView, QHBoxLayout, QLabel,
    QPushButton, QLineEdit, QComboBox, QSpinBox, QMessageBox,
    QMenu, QFileDialog, QHeaderView, QSplitter, QFrame
)
from PySide6.QtCore import Qt, QSortFilterProxyModel, QTimer, Signal
from PySide6.QtGui import QStandardItemModel, QStandardItem, QColor, QBrush, QAction
import pandas as pd
import numpy as np
import os
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure


class CurveDataDialog(QDialog):
    """曲线数据详情对话框"""

    data_exported = Signal(str)  # 数据导出信号，发送导出的文件路径

    def __init__(self, data: pd.DataFrame, parent=None, title: str = "详细数据"):
        super().__init__(parent)
        self.setWindowTitle(title)
        self.resize(1000, 700)
        self.setWindowFlags(self.windowFlags() | Qt.WindowMaximizeButtonHint)

        # 确保数据不为空
        if data is None or data.empty:
            QMessageBox.warning(self, "警告", "没有可用的数据")
            self._empty = True
            return
        else:
            self._empty = False

        # 保存原始数据
        self.original_data = data.copy()
        self.display_data = data.copy()

        # 初始化UI
        self._init_ui()

        # 加载数据
        self._load_data()

    def _init_ui(self):
        """初始化用户界面"""
        main_layout = QVBoxLayout(self)

        # 顶部搜索和过滤区域
        filter_layout = QHBoxLayout()

        # 搜索框
        search_label = QLabel("搜索:")
        self.search_edit = QLineEdit()
        self.search_edit.setPlaceholderText("输入关键词搜索...")
        self.search_edit.textChanged.connect(self._filter_data)

        # 搜索列选择
        self.search_column_combo = QComboBox()
        self.search_column_combo.addItem("所有列")

        # 应用按钮
        apply_btn = QPushButton("应用筛选")
        apply_btn.clicked.connect(self._apply_filter)

        # 重置按钮
        reset_btn = QPushButton("重置")
        reset_btn.clicked.connect(self._reset_filter)

        # 每页显示行数
        rows_label = QLabel("每页行数:")
        self.rows_spin = QSpinBox()
        self.rows_spin.setRange(10, 1000)
        self.rows_spin.setValue(100)
        self.rows_spin.valueChanged.connect(self._update_pagination)

        # 添加到布局
        filter_layout.addWidget(search_label)
        filter_layout.addWidget(self.search_edit)
        filter_layout.addWidget(self.search_column_combo)
        filter_layout.addWidget(apply_btn)
        filter_layout.addWidget(reset_btn)
        filter_layout.addWidget(rows_label)
        filter_layout.addWidget(self.rows_spin)
        filter_layout.addStretch()

        main_layout.addLayout(filter_layout)

        # 创建分割器
        splitter = QSplitter(Qt.Vertical)

        # 表格视图
        self.table_model = QStandardItemModel()
        self.proxy_model = QSortFilterProxyModel()
        self.proxy_model.setSourceModel(self.table_model)
        self.proxy_model.setFilterCaseSensitivity(Qt.CaseInsensitive)

        self.table_view = QTableView()
        self.table_view.setModel(self.proxy_model)
        self.table_view.setSortingEnabled(True)  # 启用排序
        self.table_view.setAlternatingRowColors(True)  # 交替行颜色
        self.table_view.setSelectionBehavior(QTableView.SelectRows)  # 选择整行
        self.table_view.setEditTriggers(QTableView.NoEditTriggers)  # 禁止编辑
        self.table_view.horizontalHeader().setSectionResizeMode(QHeaderView.Interactive)  # 可调整列宽
        self.table_view.horizontalHeader().setStretchLastSection(True)  # 最后一列自动拉伸
        self.table_view.verticalHeader().setDefaultSectionSize(24)  # 设置行高

        # 右键菜单
        self.table_view.setContextMenuPolicy(Qt.CustomContextMenu)
        self.table_view.customContextMenuRequested.connect(self._show_context_menu)

        splitter.addWidget(self.table_view)

        # 数据统计面板
        self.stats_frame = QFrame()
        self.stats_frame.setFrameShape(QFrame.StyledPanel)
        self.stats_layout = QVBoxLayout(self.stats_frame)

        # 添加图表显示区域
        self.figure = Figure(figsize=(10, 4), dpi=100)
        self.canvas = FigureCanvas(self.figure)
        self.stats_layout.addWidget(self.canvas)

        # 添加统计信息标签
        self.stats_label = QLabel("数据统计信息将显示在这里")
        self.stats_layout.addWidget(self.stats_label)

        splitter.addWidget(self.stats_frame)

        # 设置分割器初始大小
        splitter.setSizes([500, 200])

        main_layout.addWidget(splitter)

        # 底部状态栏
        status_layout = QHBoxLayout()

        # 数据信息
        self.data_info_label = QLabel("")

        # 分页控制
        pagination_layout = QHBoxLayout()

        self.prev_btn = QPushButton("上一页")
        self.prev_btn.setEnabled(False)
        self.prev_btn.clicked.connect(self._prev_page)

        self.page_label = QLabel("第 1 页 / 共 1 页")

        self.next_btn = QPushButton("下一页")
        self.next_btn.setEnabled(False)
        self.next_btn.clicked.connect(self._next_page)

        pagination_layout.addWidget(self.prev_btn)
        pagination_layout.addWidget(self.page_label)
        pagination_layout.addWidget(self.next_btn)

        # 导出按钮
        export_btn = QPushButton("导出数据")
        export_btn.clicked.connect(self._export_data)

        status_layout.addWidget(self.data_info_label)
        status_layout.addStretch()
        status_layout.addLayout(pagination_layout)
        status_layout.addWidget(export_btn)

        main_layout.addLayout(status_layout)

        # 初始化分页
        self.current_page = 1
        self.total_pages = 1

    def _load_data(self):
        """加载数据到表格"""
        # 清空模型
        self.table_model.clear()

        # 设置表头
        self.table_model.setHorizontalHeaderLabels(self.display_data.columns.tolist())

        # 更新搜索列选择
        self.search_column_combo.clear()
        self.search_column_combo.addItem("所有列")
        self.search_column_combo.addItems(self.display_data.columns.tolist())

        # 加载数据
        for row_idx, row in enumerate(self.display_data.itertuples(index=False)):
            items = []
            for value in row:
                # 处理缺失值
                if pd.isna(value):
                    item = QStandardItem("nan")
                    item.setData(QBrush(QColor(255, 230, 230)), Qt.BackgroundRole)
                else:
                    item = QStandardItem(str(value))

                    # 为数字类型添加右对齐
                    if isinstance(value, (int, float, np.number)):
                        item.setTextAlignment(Qt.AlignRight | Qt.AlignVCenter)

                items.append(item)

            self.table_model.appendRow(items)

        # 调整列宽
        self.table_view.resizeColumnsToContents()

        # 更新统计信息
        self._update_statistics()

        # 更新分页
        self._update_pagination()

    def _update_pagination(self):
        """更新分页信息"""
        total_rows = self.display_data.shape[0]
        rows_per_page = self.rows_spin.value()

        # 计算总页数
        self.total_pages = max(1, (total_rows + rows_per_page - 1) // rows_per_page)

        # 确保当前页在有效范围内
        self.current_page = max(1, min(self.current_page, self.total_pages))

        # 更新按钮状态
        self.prev_btn.setEnabled(self.current_page > 1)
        self.next_btn.setEnabled(self.current_page < self.total_pages)

        # 更新页码标签
        self.page_label.setText(f"第 {self.current_page} 页 / 共 {self.total_pages} 页")

        # 更新数据信息标签
        start_row = (self.current_page - 1) * rows_per_page + 1
        end_row = min(self.current_page * rows_per_page, total_rows)
        self.data_info_label.setText(f"显示 {start_row}-{end_row} 行，共 {total_rows} 行")

        # 设置代理模型的过滤范围
        self.proxy_model.setFilterKeyColumn(-1)  # 所有列
        self.proxy_model.setFilterRegExp("")  # 清除过滤

        # 如果需要分页，设置行过滤
        if rows_per_page < total_rows:
            start = (self.current_page - 1) * rows_per_page
            end = self.current_page * rows_per_page - 1
            self.proxy_model.setFilterRole(Qt.UserRole)
            self.proxy_model.setFilterRegExp(f"^{start}-{end}$")

            # 为每一行设置行号作为UserRole数据
            for i in range(total_rows):
                for j in range(self.table_model.columnCount()):
                    row_range = f"{start}-{end}" if (start <= i <= end) else ""
                    self.table_model.item(i, j).setData(row_range, Qt.UserRole)

    def _prev_page(self):
        """上一页"""
        if self.current_page > 1:
            self.current_page -= 1
            self._update_pagination()

    def _next_page(self):
        """下一页"""
        if self.current_page < self.total_pages:
            self.current_page += 1
            self._update_pagination()

    def _filter_data(self, text):
        """根据搜索文本过滤数据"""
        column_idx = self.search_column_combo.currentIndex() - 1  # -1 是因为第一个选项是"所有列"

        # 设置过滤列
        if column_idx < 0:
            self.proxy_model.setFilterKeyColumn(-1)  # 所有列
        else:
            self.proxy_model.setFilterKeyColumn(column_idx)

        # 设置过滤文本
        self.proxy_model.setFilterRegExp(text)

    def _apply_filter(self):
        """应用筛选条件"""
        search_text = self.search_edit.text()
        column_idx = self.search_column_combo.currentIndex() - 1

        if not search_text:
            # 如果搜索文本为空，重置筛选
            self._reset_filter()
            return

        # 创建筛选后的数据
        if column_idx < 0:
            # 搜索所有列
            filtered_df = self.original_data.copy()
            mask = None

            for col in filtered_df.columns:
                try:
                    if filtered_df[col].dtype == 'object':
                        col_mask = filtered_df[col].str.contains(search_text, na=False, case=False)
                    else:
                        col_mask = filtered_df[col].astype(str).str.contains(search_text, na=False, case=False)

                    if mask is None:
                        mask = col_mask
                    else:
                        mask = mask | col_mask
                except Exception as e:
                    print(f"筛选列 {col} 时出错: {e}")

            if mask is not None:
                filtered_df = filtered_df[mask]
        else:
            # 搜索特定列
            col_name = self.original_data.columns[column_idx]
            try:
                if self.original_data[col_name].dtype == 'object':
                    filtered_df = self.original_data[
                        self.original_data[col_name].str.contains(search_text, na=False, case=False)]
                else:
                    filtered_df = self.original_data[
                        self.original_data[col_name].astype(str).str.contains(search_text, na=False, case=False)]
            except Exception as e:
                print(f"筛选列 {col_name} 时出错: {e}")
                filtered_df = pd.DataFrame()

        # 更新显示数据
        self.display_data = filtered_df

        # 重置页码
        self.current_page = 1

        # 重新加载数据
        self._load_data()

    def _reset_filter(self):
        """重置筛选条件"""
        self.search_edit.clear()
        self.search_column_combo.setCurrentIndex(0)
        self.display_data = self.original_data.copy()
        self.current_page = 1
        self._load_data()

    def _update_statistics(self):
        """更新数据统计信息"""
        if self.display_data.empty:
            self.stats_label.setText("没有数据可供统计")
            return

        # 清除图表
        self.figure.clear()

        # 计算基本统计信息
        numeric_cols = self.display_data.select_dtypes(include=[np.number]).columns
        if not numeric_cols.empty:
            try:
                stats = self.display_data[numeric_cols].describe().round(2)
                stats_text = stats.to_string()
                self.stats_label.setText(stats_text)

                # 绘制直方图
                ax = self.figure.add_subplot(111)
                if len(numeric_cols) > 0:
                    # 选择第一个数值列绘制直方图
                    col = numeric_cols[0]
                    self.display_data[col].hist(ax=ax, bins=20, alpha=0.7)
                    ax.set_title(f"{col} 分布直方图")
                    ax.set_xlabel(col)
                    ax.set_ylabel("频数")
                    self.figure.tight_layout()
                    self.canvas.draw()
            except Exception as e:
                print(f"更新统计信息时出错: {e}")
                self.stats_label.setText("统计信息更新失败")
        else:
            self.stats_label.setText("没有数值类型的数据可供统计")

    def _show_context_menu(self, position):
        """显示右键菜单"""
        index = self.table_view.indexAt(position)
        if index.isValid():
            menu = QMenu()

            # 添加复制选项
            copy_action = QAction("复制单元格", self)
            copy_action.triggered.connect(lambda: self._copy_cell(index))

            # 添加复制整行选项
            copy_row_action = QAction("复制整行", self)
            copy_row_action.triggered.connect(lambda: self._copy_row(index))

            menu.addAction(copy_action)
            menu.addAction(copy_row_action)
            menu.exec_(self.table_view.viewport().mapToGlobal(position))

    def _copy_cell(self, index):
        """复制单元格内容到剪贴板"""
        if index.isValid():
            text = self.proxy_model.data(index)
            if text:
                clipboard = self.parent().clipboard()
                clipboard.setText(text)

    def _copy_row(self, index):
        """复制整行内容到剪贴板"""
        if index.isValid():
            row = index.row()
            row_data = []
            for col in range(self.proxy_model.columnCount()):
                text = self.proxy_model.data(self.proxy_model.index(row, col))
                row_data.append(text)

            clipboard = self.parent().clipboard()
            clipboard.setText('\t'.join(row_data))

    def _export_data(self):
        """导出数据到文件"""
        if self.display_data.empty:
            QMessageBox.warning(self, "警告", "没有数据可导出")
            return

        file_path, _ = QFileDialog.getSaveFileName(
            self, "导出数据", "", "CSV文件 (*.csv);;Excel文件 (*.xlsx);;文本文件 (*.txt)"
        )

        if not file_path:
            return

        try:
            ext = os.path.splitext(file_path)[1].lower()

            if ext == '.csv':
                self.display_data.to_csv(file_path, index=False)
            elif ext == '.xlsx':
                self.display_data.to_excel(file_path, index=False, engine='openpyxl')
            elif ext == '.txt':
                self.display_data.to_csv(file_path, sep='\t', index=False)
            else:
                QMessageBox.warning(self, "警告", f"不支持的文件格式: {ext}")
                return

            QMessageBox.information(self, "成功", f"数据已成功导出到 {file_path}")
            self.data_exported.emit(file_path)

        except Exception as e:
            QMessageBox.critical(self, "错误", f"导出数据时发生错误: {str(e)}")

    def exec_(self):
        """执行对话框，如果数据为空则直接返回"""
        if self._empty:
            return QDialog.Rejected
        return super().exec_()